﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FairyGUI;
using System;
public class UIManager
{
    private static UIManager instance = new UIManager();
    public static UIManager Instance => instance;

    //用于存储已经显示的UI面板
    private Dictionary<string, GComponent> panelDic = new Dictionary<string, GComponent>();
    //注册管理
    private HashSet<string> registeredPanels = new HashSet<string>();
    //存储窗口
    private Dictionary<string, Window> windowDic = new Dictionary<string, Window>();

    private UIManager()
    {
        //默认字体
        UIConfig.defaultFont = "STHUPO";
        //公共包
        UIPackage.AddPackage("UI/Public");
        //默认音效
        UIConfig.buttonSound = (NAudioClip)UIPackage.GetItemAssetByURL("ui://Public/btnMusic");
        //适配
        GRoot.inst.SetContentScaleFactor(1365, 768, UIContentScaler.ScreenMatchMode.MatchHeight);
        //模态窗口背景色
        UIConfig.modalLayerColor = new Color(0, 0, 0, 0.5f);
    }

    /// <summary>
    /// 注册面板
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="packageName"></param>
    /// <param name="panelName"></param>
    private void RegisteredPanel<T>(string packageName, string panelName) where T:GComponent
    {
        string key = $"{packageName}_{panelName}";
        if (!registeredPanels.Contains(key))
        {
            UIObjectFactory.SetPackageItemExtension($"ui://{packageName}/{panelName}", typeof(T));
            registeredPanels.Add(key);
        }
    }

    /// <summary>
    /// 加载包
    /// </summary>
    /// <param name="pkgName"></param>
    public void LoadPackage(string pkgName)
    {
        //加载包和依赖包
        UIPackage package = UIPackage.AddPackage("UI/" + pkgName);
        //加载依赖包
        //由于从Resources文件夹中加载包 会帮助我们判断重复没有 所以这里即使重复执行也没有性能问题
        foreach (var item in package.dependencies)
        {
            UIPackage.AddPackage("UI/" + item["name"]);
        }
    }

    /// <summary>
    /// 显示面板
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="packageName"></param>
    /// <returns></returns>
    public T ShowPanel<T>(string packageName) where T:GComponent
    {
        Type panelType = typeof(T);
        string panelName = panelType.Name;
        if (panelDic.ContainsKey(panelName))
        {
            panelDic[panelName].visible = true;
            return panelDic[panelName] as T;
        }
        this.LoadPackage(packageName);
        //注册面板
        RegisteredPanel<T>(packageName, panelName);
        GComponent panel = UIPackage.CreateObject(packageName, panelName).asCom;
        GRoot.inst.AddChild(panel);
        //组件的尺寸设置与屏幕尺寸的逻辑分辨率一致
        panel.MakeFullScreen();
        //将面板组件和容器进行宽高关联,容器变化 组件也会进行变化
        //注意：需要把组件添加到Groot中之后 再去设置它
        panel.AddRelation(GRoot.inst, RelationType.Size);
        //进行批处理 DC优化
        panel.fairyBatching = true;
        //当前显示的面板存起来 用于之后的显示与隐藏
        panelDic.Add(panelName, panel);
        return panel as T;
    }

    /// <summary>
    /// 隐藏面板
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="isDispose"></param>
    public void HidePanel<T>(bool isDispose=false) where T:GComponent
    {
        Type panelType = typeof(T);
        string panelName = panelType.Name;
        //没有找到面板,直接返回
        if (!panelDic.ContainsKey(panelName))
            return;
        //移除销毁面板
        if (isDispose)
        {
            panelDic[panelName].Dispose();
            panelDic.Remove(panelName);
        }
        else
        {
            panelDic[panelName].visible = false;
        }
    }

    /// <summary>
    /// 获取面板
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T GetPanel<T>() where T:GComponent
    {
        Type panelType = typeof(T);
        string paneName = panelType.Name;

        if (panelDic.ContainsKey(paneName))
            return panelDic[paneName] as T;
        return null;
    }

    /// <summary>
    /// 清理面板
    /// 过场景清理时使用
    /// </summary>
    /// <param name="isGC"></param>
    public void ClearPanel(bool isGC = false)
    {
        foreach (var item in panelDic.Values)
        {
            item.Dispose();
        }
        panelDic.Clear();
        if (isGC)
        {
            //释放所有包资源
            UIPackage.RemoveAllPackages();
            //垃圾回收
            GC.Collect();
        }
    }

    /// <summary>
    /// 显示窗口
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T ShowWindow<T>(bool modal=false) where T:Window,new()
    {
        Type type = typeof(T);
        string name = type.Name;

        if (windowDic.ContainsKey(name))
        {
            windowDic[name].Show();
            return windowDic[name] as T;
        }

        T win = new T();
        win.modal = modal;
        win.Show();
        win.MakeFullScreen();

        windowDic.Add(name, win);
        return win;
    }

    /// <summary>
    /// 隐藏/销毁窗口
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="isDispose"></param>
    public void HideWindow<T>(bool isDispose = false)
    {
        Type type = typeof(T);
        string name = type.Name;

        if (!windowDic.ContainsKey(name))
            return;

        windowDic[name].Hide();
        if (isDispose)
        {
            windowDic[name].Dispose();
            windowDic.Remove(name);
        }
    }

    /// <summary>
    /// 获取窗口
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T GetWindow<T>() where T : Window
    {
        Type type = typeof(T);
        string name = type.Name;
        if (!windowDic.ContainsKey(name))
            return null;
        return windowDic[name] as T;
    }

    /// <summary>
    /// 清理窗口
    /// 过场景清理时使用
    /// </summary>
    /// <param name="isGC"></param>
    public void ClearWindow(bool isGC = false)
    {
        foreach (var item in windowDic.Values)
        {
            item.Dispose();
        }
        windowDic.Clear();
        if (isGC)
        {
            //释放所有包资源
            UIPackage.RemoveAllPackages();
            //垃圾回收
            GC.Collect();
        }
    }

    public GComponent LoadComponent(string pkgName, string resName)
    {
        this.LoadPackage(pkgName);
        GComponent component = UIPackage.CreateObject(pkgName, resName).asCom;
        //优化DrawCall
        component.fairyBatching = true;
        return component;
    }
}
